package cn.gx.kevin.common.ui;

import cn.gx.kevin.common.user.ILoginUserContext;
import cn.gx.kevin.common.utils.*;
import com.alibaba.fastjson.JSONObject;
import cn.gx.kevin.common.thread.UrlInfoThreadHodler;
import cn.gx.kevin.common.user.LoginUser;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.MultiValueMap;

import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName: AdminControllerHelper
 * @Description: TODO
 * @author kevin.huang
 * @date 2015年12月21日 下午4:33:15
 */
public class AdminControllerHelper {

	private static Logger logger = LoggerFactory.getLogger(AdminControllerHelper.class);

	static Pattern  converPattern = Pattern.compile("(.*)_(\\w)(.*)");

	public static Map<String, Field[]> fieldMap = new HashMap<String, Field[]>();
	private static Map<String, Method> methodMap = new HashMap<String, Method>();


	public static JSONObject httpRequest(String url,Object params, Map<String,String> headParams) {
		JSONObject retObj = null;
		String param = JSONObject.toJSONString(params);
		logger.info("httpRequest is start,url = {} ,params = {}",url,param);
		CloseableHttpClient httpClient = null;
		HttpPost postRequest = null;
		try {
			httpClient = HttpClients.createDefault();
			postRequest = new HttpPost(url);
			postRequest.addHeader("Content-type", "application/json;charset=UTF-8");
			StringEntity input = new StringEntity(param,"utf-8");
			input.setContentType("application/json");
			input.setContentEncoding("utf-8");
			postRequest.setEntity(input);
			if(headParams != null && headParams.size() > 0){
				for(Map.Entry<String,String> entry : headParams.entrySet()){
					postRequest.setHeader(entry.getKey(),entry.getValue());
				}
			}
			HttpResponse response = httpClient.execute(postRequest);
			int code = response.getStatusLine().getStatusCode();
			if (code == 200) {
				logger.info("callback is sucessful,url = {}",url);
				HttpEntity returnEntity = response.getEntity();
				String responseStr = EntityUtils.toString(returnEntity);
				retObj = JSONObject.parseObject(responseStr);
				logger.info("callback is sucessful,responseStr = {}",responseStr);
			}else{
				logger.error("{} response is error ,return code {} ",url,code);
			}

		} catch (Exception ex) {
			logger.error("",ex);
		}  finally{
			if(httpClient != null){
				try {
					postRequest.clone();
				} catch (Exception e) {
				}
				try {
					httpClient.close();
				} catch (Exception e) {
				}
			}
		}
		return  retObj;
	}

	/***
	 * 将数据表字段下划线规则转换java驼峰名称
	 * ***/
	public static String tableField2javaField(String fieldName){
		if(StringUtils.isEmpty(fieldName)){
			return fieldName;
		}
		Matcher matcher = converPattern.matcher(fieldName);
		if(matcher.find()){
			return tableField2javaField(matcher.group(1) + matcher.group(2).toUpperCase() + matcher.group(3));
		}else{
			return fieldName;
		}
	}

	/***
	 * 将java字段转换数据表字段，驼峰命名规则
	 * ***/
	public static String javaField2tableField(String fieldName){
		return StringUtils.isEmpty(fieldName) ? fieldName : fieldName.replaceAll("[A-Z]", "_$0").toLowerCase();
	}


	/***在应用根目录下创建 dirName目录，不需要/开头拼接
	 * @param dirName
	 * @param request
	 * @return 返回的路径
	 */
	public static String createDir(String dirName, HttpServletRequest request) {
		if(StringUtils.isNotEmpty(dirName)){
			dirName = dirName + File.separator;
		}
		String rootDir =  request.getServletContext().getRealPath("/");
		String dirString = rootDir + dirName;
		File file = new File(dirString);
		if (file.exists()) {
			return dirString;
		}
		file.mkdirs();
		return dirString ;
	}


	/**
	 * 从请求体重获取json提交的参数对象
	 * **/
	public static JSONObject getParamFromEntityRequest(HttpServletRequest request){
		String contentType = request.getContentType();
		if (contentType != null && contentType.contains("application/json") ) {
			StringBuilder sb = new StringBuilder();
			try {
				BufferedReader reader = request.getReader();
				char[] buff = new char[1024];
				int len;
				while ((len = reader.read(buff)) != -1) {
					sb.append(buff, 0, len);
				}
			} catch (IOException e) {
				logger.error("",e);
			}
			String json = sb.toString();
			if(json.contains("&") && json.contains("=")){
				String []arr = json.split("&");
				JSONObject object = new JSONObject();
				for(String s : arr){
					String [] keyVal = s.split("=");
					object.put(keyVal[0],keyVal[1]);
				}
				return  object;
			}else{
				return JSONObject.parseObject(json);
			}
		}else{
			Map<String, String[]> map =	request.getParameterMap();
			JSONObject prs = new JSONObject();
			for(Map.Entry<String,String[]> entry : map.entrySet()){
				prs.put(entry.getKey(),entry.getValue()[0]);
			}
			return prs;
		}
	}


	public static String urlDecoder(String str) {
		String data = str;
		try {
			data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
			data = data.replaceAll("\\+", "%2B");
			data = URLDecoder.decode(data, "utf-8");
		} catch (Exception e) {
			logger.error("",e);
		}
		return data;
	}


	public static UrlInfo getControllerAndCmd(HttpServletRequest request) {
		UrlInfo info = UrlInfoThreadHodler.get();
		if (info == null) {
			info = new UrlInfo();
			String requestUrl = request.getRequestURI().replaceAll("//","/");
			String contextPath = request.getContextPath() + "/";
			info.setCtx(contextPath);
			if (requestUrl.equals(contextPath)) {
				info.setRootRequest(true);
			}
			info.setUrl(requestUrl);
			String tmpStr = requestUrl;
			if (!"/".equals(contextPath)) {
				tmpStr = requestUrl.replace(contextPath, "");
			}				
			String method = request.getMethod();
			info.setMethod(method);
			// 按规范 此为请求页面的url
			if ("GET".equals(method) && requestUrl.contains("/page/")) {
				tmpStr = tmpStr.replaceAll("/page/\\S*", "/page");
			}

			String[] tmpArr = tmpStr.split("/");
			StringBuffer controller = new StringBuffer();
			controller.append("/");
			String cmdString = null;
			for (int i = 0, len = tmpArr.length; i < len; ++i) {
				if (i < len - 1) {
					controller.append(tmpArr[i]);
					if (i < len - 2) {
						controller.append("/");
					}						
				} else {
					cmdString = tmpArr[i];
				}
			}
			String cmdParam = request.getParameter("cmd");
			if (StringUtils.isNoneEmpty(cmdParam)) {
				cmdString = cmdParam;
			}

			String authorCtrlString = request.getParameter("authctl");

			if (StringUtils.isNotEmpty(authorCtrlString)) {
				info.setAuthController(authorCtrlString);
			}

			info.setController(controller.toString().replace("//", "/"));
			info.setCmd(cmdString);

			UrlInfoThreadHodler.set(info);

			if (logger.isDebugEnabled()) {
				logger.debug(info.toString());
			}
		}
		request.setAttribute("cmd", info.getCmd());
		return info;
	}

	/**
	 * @Title: getObjectFromRquest @Description: 从请求中提前数据创建实体对象 @param formObject
	 *         可以是HttpServletRequest 或者 map<String,String>集合 @param entityClass
	 *         实体类的class @param idClass id属性的class @param isUpdated 是否是用于更新操作的
	 *         createUserId、createTime特殊字段处理 @return @throws
	 */
	@SuppressWarnings("unchecked")
	public static <T extends Serializable> T getObjectFromRequest(LoginUser user, Object formObject,
			Class<?> entityClass, Class<?> idClass, boolean isUpdated) throws Exception {
		boolean isRequest = formObject instanceof HttpServletRequest;
		boolean isJsonObject = false;
		if(isRequest){
			HttpServletRequest request = 	(HttpServletRequest) formObject;
			String contentType = request.getContentType();
			if (contentType != null && contentType.contains("application/json") ) {
				formObject =	getParamFromEntityRequest(request);
				isJsonObject = true;
			}
		}
		T bean = (T) entityClass.newInstance();
		for (Class<?> superClass = entityClass; superClass != Object.class; superClass = superClass.getSuperclass()) {
			String clsName = entityClass.getName();
			Field[] fields = fieldMap.get(clsName);
			if (fields == null) {
				fields = superClass.getDeclaredFields();
				fieldMap.put(clsName, fields);
			}
			for (Field field : fields) {
				String fieldName = field.getName();
				if (fieldName.equalsIgnoreCase("serialVersionUID")) {
					continue;
				}
				String tmpVal = null;
				if (isRequest) {
					tmpVal = ((HttpServletRequest) formObject).getParameter(fieldName);
				} else if(isJsonObject){
					tmpVal = ((JSONObject)formObject).getString(fieldName);
				}else{
					tmpVal = ((Map<String, String>) formObject).get(fieldName);
				}
				boolean isCreateTime = fieldName.equalsIgnoreCase("createTime");
				boolean isCreateUser = fieldName.equalsIgnoreCase("createUserId");
				if(isUpdated && (isCreateTime || isCreateUser)){
					continue;
				}
				// 特殊字段处理
				if (!isUpdated && isCreateTime) {
					tmpVal = DateUtils.formatCurrentDateTime("yyyy-MM-dd HH:mm:ss");
				}
				if (!isUpdated && isCreateUser) {
					tmpVal = String.valueOf(user.getId());// 测试注释
				}
				if(fieldName.equalsIgnoreCase("updateTime")) {
					tmpVal = DateUtils.formatCurrentDateTime("yyyy-MM-dd HH:mm:ss");
				}
				if(fieldName.equalsIgnoreCase("updateUserId")) {
					tmpVal = String.valueOf(user.getId());
				}
				if (tmpVal == null) {
					continue;
				}					
				String fvalue = tmpVal;// URLDecoder.decode(tmpVal,"utf-8");
				PropertyDescriptor pd = null;
				String methodKey = clsName + fieldName;
				Method method = methodMap.get(methodKey);
				if (method == null) {
					try {
						pd = new PropertyDescriptor(fieldName, entityClass);
						method = pd.getWriteMethod();
						method.setAccessible(true);
						methodMap.put(methodKey, method);
					} catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}
				Class<?> clazz = field.getType();
				if ("id".equals(fieldName)) {
					clazz = idClass;
				}
				if (clazz.isArray()) {
					// 待实现
				} else if (clazz.isEnum()) {
					// 待实现
				} else {
					String simpleName = clazz.getSimpleName().toLowerCase();
					if (simpleName.equalsIgnoreCase("string")) {
						method.invoke(bean, fvalue);
					} else if (simpleName.equalsIgnoreCase("date")) {
						if (!fvalue.equalsIgnoreCase("")) {
							if (fvalue.matches("\\d{4}-\\d{2}$")) {
								method.invoke(bean, DateUtils.parseDateTime(fvalue +"-01", "yyyy-MM-dd"));
							}else if (fvalue.matches("\\d{4}-\\d{2}-\\d{2}$")) {
								method.invoke(bean, DateUtils.parseDateTime(fvalue, "yyyy-MM-dd"));
							}else if(fvalue.matches("\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}$")){
								method.invoke(bean, DateUtils.parseDateTime(fvalue, "yyyy-MM-dd HH:mm"));
							}else {
								method.invoke(bean, DateUtils.parseDateTime(fvalue, "yyyy-MM-dd HH:mm:ss"));
							}
						}
					} else if (simpleName.equalsIgnoreCase("boolean")) {
						String tmp = fvalue.toLowerCase();
						if (tmp.equalsIgnoreCase("0") || tmp.equalsIgnoreCase("false")) {
							method.invoke(bean, false);
						} else {
							method.invoke(bean, true);
						}
					} else {
						if (!fvalue.equalsIgnoreCase("")) {
							Object obj = ConvertUtils.convert(fvalue, clazz);
							method.invoke(bean, obj);
						}
					}
				}
			}
		}
		return bean;
	}

	public static <T extends Serializable, K extends Serializable> String validEntityBean(T bean,
			HashSet<String> excFileds, IServiceValid svcValuid, HttpServletRequest request) {
		AnnotationValid<T, K> valid = new AnnotationValid<T, K>();
		String validRes;
		try {
			validRes = valid.valid(bean, excFileds, svcValuid, request);
		} catch (Throwable e) {
			validRes = "validate is expction！";
			logger.error("", e);
		}
		return validRes.toString();
	}

	public static boolean delFile(File file) {
		if (!file.exists()) {
			return false;
		}
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			if(files != null){
				for (File f : files) {
					delFile(f);
				}
			}
		}
		return file.delete();
	}

	public static void responseJson(HttpServletResponse response, int code, String message,Object data){
		AjaxResult result = new AjaxResult(code,message);
		result.data = data;
		try{
			response.setContentType("text/html;charset=UTF-8");
			response.setCharacterEncoding("utf-8");
			String json = JSONObject.toJSONString(result);
			response.getWriter().write(json);
			response.flushBuffer();
		}catch (Exception x){
			logger.error("",x);
		}
	}

    public static void responseText(HttpServletResponse response,  String message){
        try{
            response.setContentType("text/html;charset=UTF-8");
            response.setCharacterEncoding("utf-8");
            response.getWriter().write(message);
            response.flushBuffer();
        }catch (Exception x){
            logger.error("",x);
        }
    }

	public static Map<String, List<MultipartFile>> getMultipartFile(HttpServletRequest request) {
		Map<String, List<MultipartFile>> fileMap = new HashMap<>();
		if (ServletFileUpload.isMultipartContent(request)) {// 判断表单中是否存在文件
			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
			MultiValueMap<String, MultipartFile> files = multipartRequest.getMultiFileMap();
			Set<Map.Entry<String,List<MultipartFile>>> sets = files.entrySet();
			for(Map.Entry<String,List<MultipartFile>> entry : sets) {
				fileMap.put(entry.getKey(), entry.getValue());
			}
		}
		return fileMap;
	}

	/**
	 * 请在外部往ServletOutputStream写好需要下载的内容
	 * @param response
	 * @param fileName
	 * @param contentType "application/octet-stream"  "application/msexcel"
	 * @throws Exception
	 */
	public static void responseFile(HttpServletResponse response, String fileName, String contentType) throws  Exception{
		responseFile(response,fileName,contentType,null);
	}
	/**
	 *
	 * @param response
	 * @param fileName  文件名
	 * @param contentType "application/octet-stream"  "application/msexcel"
	 * @param  fileInputStream 需要下载的文件流，可以为null,在外部,内部用完后，会直接关闭
	 * @throws Exception
	 */
	public static void responseFile(HttpServletResponse response, String fileName, String contentType, FileInputStream fileInputStream) throws  Exception{
		response.setCharacterEncoding("utf-8");
		response.setHeader("Content-disposition",
				"attachment; filename=" + new String(fileName.getBytes("gb2312"), "iso-8859-1")); // 设定输出文件头
		response.setContentType(contentType); // 定义输出类型
		ServletOutputStream outputStream = response.getOutputStream();
		if(fileInputStream != null){
			byte[] buffer = new byte[fileInputStream.available()];
			int i = -1;
			while ((i = fileInputStream.read(buffer)) != -1) {
				outputStream.write(buffer, 0, i);
			}
			fileInputStream.close();
		}
		response.flushBuffer();
	}

	/**
	 * @param data
	 * @param skipNull
	 * @return
	 */
	public static String toJsonString(Object data, boolean skipNull) {
		return toJsonString(data, null, null, skipNull,"yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * @param data         数据
	 * @param skipFileds   不需要转换的字段
	 * @param formatFileds 设置字段格式化，只支持date属性
	 * @param skipNull     是否跳过null字段，默认false
	 * @return
	 */
	public static String toJsonString(Object data, final HashSet<String> skipFileds,final Map<String, String> formatFileds,final boolean skipNull,String dateTimeFormat) {
		PropertyFilter propFilter = null;
		List<SerializeFilter> allFilters = new ArrayList<SerializeFilter>();
		if (skipFileds != null) {
			propFilter = new PropertyFilter() {
				@Override
				public boolean apply(Object object, String name, Object value) {
					if (skipFileds.contains(name)) {
						return false;
					}
					if (skipNull && value == null) {
						return false;
					}
					return true;
				}
			};
			allFilters.add(propFilter);
		}
		ValueFilter valFilter = null;
		if (formatFileds != null) {
			valFilter = new ValueFilter() {
				@Override
				public Object process(Object object, String name, Object value) {
					if (value == null) {
						return value;
					}
					String fieldType = value.getClass().getSimpleName();
					if (fieldType.equals("Date")) {
						String format = formatFileds.get(name);
						Date dateVal = (Date) value;
						if (format != null) {
							return DateUtils.formatDateTime(dateVal, format);
						}else{
							return DateUtils.formatDateTime(dateVal, dateTimeFormat);
						}
					}
					return value;
				}
			};
			allFilters.add(valFilter);
		}
		return JSONObject.toJSONString(data, allFilters.toArray(new SerializeFilter[allFilters.size()]),
				SerializerFeature.PrettyFormat);

	}

	/***
	 * 将json转为实体bean
	 * @param json  json字符串
	 * @param clazz bean的class
	 * @param <E>  泛型声明
	 * @return 返回bean
	 */
	public static <E> E json2Object(String json,Class<E> clazz){
		E obj = JSONObject.parseObject(json,clazz);
		return obj;
	}


	public static  void setDownLoadFlag(HttpServletRequest request,ILoginUserContext userContext) throws Exception{
		String key = request.getParameter("_down_key_");
		if(userContext != null){
			userContext.setKeyValue(key,1);
		}
	}

	public static  void clearDownLoadFlag(HttpServletRequest request,ILoginUserContext userContext) throws Exception{
		String key = request.getParameter("_down_key_");
		if(userContext != null){
			userContext.deleteKeyValue(key);
		}
	}


	public static 	AjaxResult checkresponse(ILoginUserContext userContext,HttpServletRequest request)
			throws Throwable {
		String finish_down_key = request.getParameter("k_finish_down_key_");
		AjaxResult result = new AjaxResult(0,"");
		if(userContext == null){
			return result;
		}
		Object flag = userContext.getKeyValue(finish_down_key);
		if (flag == null) {
			String msg = LanguageStore.getValueByKey(SysConfigParams.lang,"common_load_succ");
			result.message = msg;
			return result;
		}
		return result;
	}

	/*****
	 * 替换参数中的../ 相对目录，避免漏洞
	 * ******/
	public static String replaceRelativePathParam(String str) {
		return str.replaceAll("../", "");
	}


}
